package com.haohan.cloud.scm.opc.core.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.haohan.cloud.scm.api.bill.dto.OrderDetailDTO;
import com.haohan.cloud.scm.api.bill.dto.OrderInfoDTO;
import com.haohan.cloud.scm.api.constant.enums.bill.OrderTypeEnum;
import com.haohan.cloud.scm.api.constant.enums.opc.ShipRecordStatusEnum;
import com.haohan.cloud.scm.api.opc.entity.ShipRecord;
import com.haohan.cloud.scm.api.opc.entity.ShipRecordDetail;
import com.haohan.cloud.scm.api.opc.entity.Shipper;
import com.haohan.cloud.scm.api.opc.req.ship.EditShipRecordReq;
import com.haohan.cloud.scm.api.opc.req.ship.QueryShipRecordReq;
import com.haohan.cloud.scm.api.opc.req.ship.QueryShipperReq;
import com.haohan.cloud.scm.api.opc.trans.ShipTrans;
import com.haohan.cloud.scm.api.opc.vo.ShipRecordDetailVO;
import com.haohan.cloud.scm.api.opc.vo.ShipRecordVO;
import com.haohan.cloud.scm.common.tools.exception.ErrorDataException;
import com.haohan.cloud.scm.common.tools.thread.ScmGlobalThreadPool;
import com.haohan.cloud.scm.opc.core.ShipManageCoreService;
import com.haohan.cloud.scm.opc.service.ShipRecordDetailService;
import com.haohan.cloud.scm.opc.service.ShipRecordService;
import com.haohan.cloud.scm.opc.service.ShipperService;
import com.haohan.cloud.scm.opc.utils.ScmOpcOrderFactory;
import com.haohan.cloud.scm.opc.utils.ScmOpcUtils;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author dy
 * @date 2020/1/6
 */
@Service
@AllArgsConstructor
public class ShipManageCoreServiceImpl implements ShipManageCoreService {

    private final ShipRecordService shipRecordService;
    private final ShipRecordDetailService shipRecordDetailService;
    private final ShipperService shipperService;
    private final ScmOpcUtils scmOpcUtils;

    @Override
    public IPage<ShipRecord> fetchPage(Page page, QueryShipRecordReq req) {
        LocalDate start = req.getStartDate();
        LocalDate end = req.getEndDate();
        boolean flag = null != start && null != end;

        return shipRecordService.page(new Page<>(page.getCurrent(), page.getSize()), Wrappers.query(req.transTo()).lambda()
                .like(StrUtil.isNotEmpty(req.getCustomerName()), ShipRecord::getCustomerName, req.getCustomerName())
                .like(StrUtil.isNotEmpty(req.getReceiverName()), ShipRecord::getReceiverName, req.getReceiverName())
                .like(StrUtil.isNotEmpty(req.getShipperName()), ShipRecord::getShipperName, req.getShipperName())
                .like(StrUtil.isNotEmpty(req.getLogisticsName()), ShipRecord::getLogisticsName, req.getLogisticsName())
                .apply(flag, "DATE(ship_time) between {0} and {1}", start, end)
                .orderByDesc(ShipRecord::getCreateDate)
        );
    }

    @Override
    public ShipRecordVO fetchInfo(String shipSn) {
        ShipRecord exist = shipRecordService.fetchBySn(shipSn);
        if (null == exist) {
            throw new ErrorDataException("发货记录有误");
        }
        return fetchInfo(exist);
    }

    private ShipRecordVO fetchInfo(ShipRecord exist) {
        List<ShipRecordDetail> detailList = shipRecordDetailService.fetchListBySn(exist.getShipRecordSn());
        if (CollUtil.isEmpty(detailList)) {
            throw new ErrorDataException("发货记录明细有误");
        }
        ShipRecordVO result = new ShipRecordVO(exist);
        result.setDetailList(detailList.stream().map(ShipRecordDetailVO::new).collect(Collectors.toList()));
        return result;
    }

    @Override
    public ShipRecordVO fetchInfoByOrderSn(String orderSn) {
        ShipRecord exist = shipRecordService.fetchByOrderSn(orderSn);
        if (null == exist) {
            throw new ErrorDataException("发货记录有误");
        }
        return fetchInfo(exist);
    }

    /**
     * 根据订单创建发货记录(已存在发货记录则修改)
     *
     * @param orderSn
     * @param orderType
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public ShipRecord createShipRecordByOrder(String orderSn, OrderTypeEnum orderType) {
        // 已存在发货记录则修改
        ShipRecord exist = shipRecordService.fetchByOrderSn(orderSn);
        OrderInfoDTO order = scmOpcUtils.fetchOrderInfo(orderSn, orderType);
        if (null == exist) {
            // 通过订单初始化  状态：未发货
            ShipRecord shipRecord = ShipTrans.initShipRecord(order);
            shipRecordService.save(shipRecord);
            String shipSn = shipRecord.getShipRecordSn();
            // 发货单明细
            for (OrderDetailDTO orderDetail : order.getDetailList()) {
                ShipRecordDetail detail = ShipTrans.copyFromOrderDetail(orderDetail);
                detail.setShipRecordSn(shipSn);
                shipRecordDetailService.save(detail);
            }
            return shipRecord;
        }
        // 修改为初始值
        ShipRecord update = ShipTrans.initShipRecord(order);
        update.setId(exist.getId());
        shipRecordService.updateById(update);
        // 明细修改
        shipRecordDetailService.remove(Wrappers.<ShipRecordDetail>query().lambda()
                .eq(ShipRecordDetail::getShipRecordSn, exist.getShipRecordSn())
        );
        // 发货单明细
        for (OrderDetailDTO orderDetail : order.getDetailList()) {
            ShipRecordDetail detail = ShipTrans.copyFromOrderDetail(orderDetail);
            detail.setShipRecordSn(exist.getShipRecordSn());
            shipRecordDetailService.save(detail);
        }
        return update;
    }

    @Override
    public boolean createShipRecordBatchByOrder(Set<String> orderSnSet, OrderTypeEnum orderType) {
        if (CollUtil.isEmpty(orderSnSet) || null == orderType) {
            return false;
        }
        // 排除已创建过的发货单
        List<ShipRecord> shipList = shipRecordService.list(Wrappers.<ShipRecord>query().lambda()
                .in(ShipRecord::getOrderSn, orderSnSet)
        );
        shipList.forEach(item -> orderSnSet.remove(item.getOrderSn()));
        orderSnSet.forEach(orderSn -> ScmGlobalThreadPool.getExecutor()
                .execute(() -> createShipRecordByOrder(orderSn, orderType))
        );
        return true;
    }

    /**
     * 完成发货操作
     * 选择发货人，物流公司
     *
     * @param req
     * @return
     */
    @Override
    public ShipRecord completeShip(EditShipRecordReq req) {
        ShipRecord shipRecord = shipRecordService.fetchBySn(req.getShipRecordSn());
        if (null == shipRecord) {
            throw new ErrorDataException("发货记录有误");
        }
        Shipper shipper = shipperService.getById(req.getShipperId());
        if (null == shipper) {
            throw new ErrorDataException("发货人有误");
        }
        ShipRecord update = req.copyToEdit();
        update.setId(shipRecord.getId());
        update.setShipperName(shipper.getShipperName());
        update.setShipperTelephone(shipper.getTelephone());
        update.setShipAddress(shipper.getShipAddress());
        update.setShipTime(LocalDateTime.now());
        update.setShipStatus(ShipRecordStatusEnum.success);
        shipRecordService.updateById(update);
        BeanUtil.copyProperties(update, shipRecord);
        // 完成发货时修改订单状态
        ScmOpcOrderFactory.getOrderService(shipRecord.getOrderType()).orderCompleteShip(shipRecord.getOrderSn());
        return shipRecord;
    }

    @Override
    public IPage<Shipper> fetchShipperPage(Page page, QueryShipperReq req) {
        return shipperService.page(new Page<>(page.getCurrent(), page.getSize()), Wrappers.<Shipper>query()
                .orderByAsc("sort + 0", "create_date")
                .lambda()
                .eq(null != req.getSex(), Shipper::getSex, req.getSex())
                .like(StrUtil.isNotEmpty(req.getShipperName()), Shipper::getShipperName, req.getShipperName())
                .like(StrUtil.isNotEmpty(req.getTelephone()), Shipper::getTelephone, req.getTelephone())
                .like(StrUtil.isNotEmpty(req.getShipAddress()), Shipper::getShipAddress, req.getShipAddress())
        );
    }

    /**
     * 删除发货记录 (不为已发货)
     *
     * @param orderSn
     * @param orderType
     * @return
     */
    @Override
    public boolean deleteShipRecordByOrder(String orderSn, OrderTypeEnum orderType) {
        ShipRecord record = shipRecordService.fetchByOrderSn(orderSn);
        if (null == record) {
            return true;
        }
        if (record.getShipStatus() == ShipRecordStatusEnum.success) {
            return false;
        }
        return shipRecordService.removeById(record.getId());
    }

    @Override
    public boolean updateMerchantName(String pmId, String pmName) {
        if (StrUtil.isEmpty(pmId) || StrUtil.isEmpty(pmName)) {
            throw new ErrorDataException("缺少参数pmId、pmName");
        }
        ShipRecord update = new ShipRecord();
        update.setPmName(pmName);
        return shipRecordService.update(update, Wrappers.<ShipRecord>query().lambda()
                .eq(ShipRecord::getPmId, pmId)
        );
    }

    /**
     * 根据订单信息更新发货记录  (不为已发货)
     *
     * @param orderSn
     * @param orderType
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateShipRecordByOrder(String orderSn, OrderTypeEnum orderType) {
        ShipRecord record = shipRecordService.fetchByOrderSn(orderSn);
        if (null == record) {
            return true;
        }
        if (record.getShipStatus() == ShipRecordStatusEnum.success) {
            throw new ErrorDataException("发货状态不能为已发货");
        }
        createShipRecordByOrder(orderSn, orderType);
        return true;
    }
}
